/* 朱刘算法 最小树形图 O(nm)
* 1.最小有向树形图
    最小树形图是有向图中以某个点为根，连接所有其他点的最小权值的有向树
    有向 && 每个点入度为1(仅从父节点连向子节点)

* 2.朱刘算法 每个非根顶点选择最小入边
    1 贪心 从每个点的所有入边中找一条权值最小的边
    2 从选出的边中判断是否存在环
        2.1 不存在环，结束，把所有边权值加上作为答案
        2.2 存在环，进入第3步
    3 将所有环缩点，构造新图G'，缩点前把所有边权值加上
        3.1 环内的边 删去 
        3.2 终点在环内的边 更新权值 w' = w - 终点入边权值
        3.3 其他边 不变
    每次缩一次点,点数最少-1,所以总共最多迭代n次算法结束。

* 3.证明
    1 环中的边一定至少要去掉一条边
    2 一定存在一个最优解，只去一条边
        假设去了两条环内边，则说明环内有两个点的入边权值变大
    3 缩点前和缩点后的树形图的最小权值相等--则要求G的最小权和==G'的最小权和
        任给G中的一个树形图一定能找到一种变换变换到对应的G'
        任给G'中的一个树形图一定能找到对应的G
*/

#define DEBUG
#pragma GCC optimize("O1,O2,O3,Ofast")
#pragma GCC optimize("no-stack-protector,unroll-loops,fast-math,inline")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse,sse2,sse3,sse4,sse4.1,sse4.2,ssse3")

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;


const int N = 110, INF = 0x3f3f3f3f;
using PDD = pair<double, double>;
#define x first
#define y second

int n, m;
int dfn[N], low[N], timestamp, stk[N], top;
int scc[N], cnt; //缩点后新图
bool instk[N];
/*
    dfn[N]：时间戳数组，dfn[u] 表示节点 u 在深度优先搜索中第一次被访问的时间戳。时间戳从 1 开始递增。
    low[N]：追溯值数组，low[u] 表示节点 u 及其子孙节点能够追溯到的最早的时间戳。
    timestamp：时间戳计数器，初始值为 0，每次访问一个新节点时，timestamp 加 1。
    stk[N]：栈数组，用于存储当前正在访问的节点。在深度优先搜索过程中，将节点依次压入栈中。
    top：栈顶指针，初始值为 0，表示栈为空。
    scc[N]：强连通分量编号数组，scc[u] 表示节点 u 所属的强连通分量的编号。强连通分量的编号从 1 开始递增。
    cnt：强连通分量的数量，初始值为 0。
    instk[N]：标记数组，instk[u] 表示节点 u 是否在栈中。
*/
PDD point[N]; //记录所有点的坐标
bool g[N][N]; //邻接矩阵
double d[N][N], bd[N][N]; //距离 备份数据
int pre[N], bpre[N]; ////每个点选择的前驱点(入边连的起始点) 备份数组
bool st[N]; //是否能搜索到

void dfs(int u)
{
    // printf("%d ", u);
    st[u]=true;
    for(int i=1; i<=n; i++)
        if(g[u][i] && !st[i]) //u->i && i没有访问过
            dfs(i);
}

bool check_con() //判断整个图是否有连通性
{
    memset(st, 0, sizeof st);
    dfs(1); //从1号点深搜
    for(int i=1; i<=n; i++)
        if(!st[i])
            return false; //存在点搜索不到
    return true;
}

double get_dist(int a, int b) //计算距离
{
    double dx = point[a].x - point[b].x;
    double dy = point[a].y - point[b].y;
    return sqrt(dx * dx + dy * dy);
}


void Tarjan(int u)
{
    dfn[u] = low[u] = ++timestamp;
    stk[++top]=u, instk[u]=true;
    //每个点有且只有一条入边，不需要循环
    int v=pre[u]; //u的前驱点
    if(!dfn[v]) //没搜过，用low[v]更新low[u]
    {
        Tarjan(v);
        low[u]=min(low[u], low[v]);
    }
    else if(instk[v]) //在栈中，用dfn[v]更新low[u]
        low[u]=min(low[u], dfn[v]);
    if(low[u] == dfn[u]) //比u低的v都dfs完了，回到最高点u，把比u低的v出栈
    {
        int v;
        cnt++;
        do
        {
            v=stk[top--], instk[v]=false, scc[v]=cnt;
        } while (v != u);
        
    }
}

double solve()
{
    double res = 0;
    // 初始化距离矩阵
    for(int u=1; u<=n; u++)
        for(int v=1; v<=n; v++)
            if (g[u][v]) d[u][v] = get_dist(u, v); //有边，计算实际距离
            else d[u][v] = INF; //无边

    while(true)
    {
        // 求所有入边的最小值
        for(int u=1; u<=n; u++)
        {
            pre[u] = u;// 入边首先初始化为自己到自己的INF，每个点都为一个强连通分量
            for(int v=1; v<=n; v++)
                if (d[pre[u]][u] > d[v][u])
                    pre[u] = v;
        }

        //Tarjan
        memset(dfn, 0, sizeof dfn);//初始化dfn序
        timestamp=cnt=0; //初始化时间戳
        for(int i=1; i<=n; i++)
            if(!dfn[i])
                Tarjan(i);

        if(cnt == n) //没有环，所有边的权重和即为答案
        {
            for(int i=2; i<=n; i++) res += d[pre[i]][i];
            break;
        }

        //有环，累加所有边
        for(int i=2; i<=n; i++)
            if(scc[pre[i]] == scc[i]) //起点和终点在同一个强连通分量中->边在环中
                res += d[pre[i]][i];
            
        //初始化bd数组，作为G'的距离
        for(int i=1; i<=cnt; i++)
            for(int j=1; j<=cnt; j++)
                bd[i][j]=INF;

        //构建G‘ 用备份数组记录缩点后图中每个点直接的边权
        for(int u=1; u<=n; u++)
            for(int v=1; v<=n; v++)
                if(d[u][v]<INF && scc[u]!=scc[v]) //u->v 并且u,v不在同一个强连通分量中(该边为环外边)->缩点后仍存在的边
                {
                    int i=scc[u], j=scc[v]; //u,v的所在圈(子树)的可回溯最高点i,j
                    //v和v的前驱点在同一个强连通分量中，终点在环内，入边w'=w-[环内入边权]= d[u][v] - d[pre[v]][v]
                    if(scc[pre[v]]==scc[v]) bd[i][j] = min(bd[i][j], d[u][v] - d[pre[v]][v]);
                    else bd[i][j] = min(bd[i][j], d[u][v]); //更新最短距离
                }
        //更换新图
        n=cnt; //n为更新点数，d更新为bd
        memcpy(d, bd, sizeof d);
        
    }
    return res;
}



int main()
{
    #ifdef DEBUG
        freopen("./in.txt","r",stdin);
    #else
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    #endif

    while(cin >> n >> m)
    {
        for(int i=1; i<=n; i++) cin >> point[i].x >> point[i].y;
        memset(g, 0, sizeof g);
        while(m--)
        {
            int a, b; cin >> a >> b;
            if(a!=b && b!=1) g[a][b] = true;
        }
        if(!check_con()) puts("poor snoopy");//不连通 无解
        else printf("%.2lf\n", solve());
    }
    return 0;
}